//################################################################################
// MIT License
// Copyright (c) 2024 ZhangYihua
//
// Change Logs:
// Date           Author       Notes
// 2020-10-14     ZhangYihua   first version
//
// Description  : signed data saturation and truncation, then registered
//################################################################################

module ds_sat_tru_reg #(     // range [-(2^(IDW-1))/(2^IFW):(2^(IDW-1)-1)/(2^IFW)]
parameter           IDW                     = 9,    // input data width
parameter           IFW                     = 5,    // input fractional width,  IFW>=IDW is legal
parameter           ODW                     = 7,    // output data width
parameter           OFW                     = 4,    // output fractional width, OFW>=ODW is legal
parameter           TRU_MODE                = "CBB_DEFINE"  // default truncation mode follows cbb_define.v 
//parameter           TRU_MODE                = "FLOOR"   // discade fractional bits directly for less area and higher Fmax
//parameter           TRU_MODE                = "ROUND"   // discade or carry according to MSB of fractonal bits for better DC
) ( 
input                                       rst_n,
input                                       clk,
input                                       cke,

input       signed  [IDW-1:0]               id_re,   // s(IDW, IFW), the MSB is sign
input       signed  [IDW-1:0]               id_im,   // s(IDW, IFW), the MSB is sign
output  reg signed  [ODW-1:0]               od_re,   // s(ODW, OFW), the MSB is sign
output  reg signed  [ODW-1:0]               od_im,   // s(ODW, OFW), the MSB is sign
output                                      over
);

//################################################################################
// define local varialbe and localparam
//################################################################################
wire                [ODW-1:0]               od_re_c;
wire                [ODW-1:0]               od_im_c;
wire                                        over_re_c;
wire                                        over_im_c;
reg                                         over_re;
reg                                         over_im;

//################################################################################
// main
//################################################################################

s_sat_tru #(     // range [-(2^(IDW-1))/(2^IFW):(2^(IDW-1)-1)/(2^IFW)]
        .IDW                            (IDW                            ),	// input data width
        .IFW                            (IFW                            ),	// input fractional width
        .ODW                            (ODW                            ),	// output data width
        .OFW                            (OFW                            ),	// output fractional width
        .TRU_MODE                       (TRU_MODE                       )
) u_re ( 
        .id                             (id_re                          ),	// s(IDW, IFW), the MSB is sign
        .od                             (od_re_c                        ),	// s(ODW, OFW), the MSB is sign
        .over                           (over_re_c                      )
);

s_sat_tru #(     // range [-(2^(IDW-1))/(2^IFW):(2^(IDW-1)-1)/(2^IFW)]
        .IDW                            (IDW                            ),	// input data width
        .IFW                            (IFW                            ),	// input fractional width
        .ODW                            (ODW                            ),	// output data width
        .OFW                            (OFW                            ),	// output fractional width
        .TRU_MODE                       (TRU_MODE                       )
) u_im ( 
        .id                             (id_im                          ),	// s(IDW, IFW), the MSB is sign
        .od                             (od_im_c                        ),	// s(ODW, OFW), the MSB is sign
        .over                           (over_im_c                      )
);

always@(posedge clk or negedge rst_n) begin
    if (rst_n==1'b0) begin
        od_re <=`U_DLY {ODW{1'b0}};
        od_im <=`U_DLY {ODW{1'b0}};
    end else if (cke==1'b1) begin
        od_re <=`U_DLY od_re_c;
        od_im <=`U_DLY od_im_c;
    end else
        ;
end

always@(posedge clk or negedge rst_n) begin
    if (rst_n==1'b0) begin
        over_re <=`U_DLY 1'b0;
        over_im <=`U_DLY 1'b0;
    end else begin
        over_re <=`U_DLY over_re_c & cke;
        over_im <=`U_DLY over_im_c & cke;
    end
end

assign over = over_re | over_im;

//################################################################################
// ASSERTION
//################################################################################

`ifdef CBB_ASSERT_ON
// synopsys translate_off

// synopsys translate_on
`endif

endmodule
